package org.videopractice.network;

import org.videopractice.common.Logger;
import org.videopractice.network.codec.MessageDecoder;
import org.videopractice.network.codec.MessageEncoder;
import org.videopractice.network.handler.SupplierMessageHandler;

import java.net.InetSocketAddress;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * 供应商服务，发送消息
 */
public class SupplierServer {

    // 监听端口
    private final int socketPort = 1215;

    // 避免使用默认线程数参数
    private static EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    // XXX 默认为cpu数，实际使用线程数会更好
    private static EventLoopGroup workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors());

    public SupplierServer() {
    }

    private void onConnect(int port) {
        try{
            ServerBootstrap supplierBootstrap = new ServerBootstrap();
            supplierBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    // BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，
                    // 用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，Java将使用默认值50
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // Netty4使用内存池，重用缓冲区 ByteBuf 需要手动释放，有可能会造成内存泄漏，API： ReferenceCountUtil.release(buf);
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            // 当有操作超出指定空闲秒数时，便会触发{@link MessageTransportHandler#userEventTriggered}事件
                            // 服务端设置读超时时间为180秒
                            pipeline.addLast(new IdleStateHandler(180, 0, 0));
                            pipeline.addLast(new MessageDecoder());
                            pipeline.addLast(new LengthFieldPrepender(4));
                            pipeline.addLast(new MessageEncoder());
		                    pipeline.addLast(new SupplierMessageHandler());
                        }
                    });

            ChannelFuture channelFuture = supplierBootstrap.bind(new InetSocketAddress(port)).sync();
            channelFuture.channel().closeFuture().sync();

            Logger.i("中控服务器已启动，开始监听客户端请求......");
        } catch (Exception e) {
            Logger.e("中控服务器启动错误");
            e.printStackTrace();
        } finally {
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
            if (workerGroup != null) {
                workerGroup.shutdownGracefully();
            }
        }

        // 优雅退出
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                if (bossGroup != null) {
                    bossGroup.shutdownGracefully();
                }
                if (workerGroup != null) {
                    workerGroup.shutdownGracefully();
                }
            }
        });
    }

    public void connect() {
        new Thread() {
            public void run() {
                try {
                    onConnect(socketPort);
                    return;
                } catch (Exception localException) {
                    localException.printStackTrace();
                }
            }
        }.start();
    }

} 
